package context

import (
	"fmt"
	"golang.org/x/net/context"
	"time"
)

// Context 用于进程或服务之间信息和信号传递，我理解相当于绑定全局变量的数据
// 场景：子协程间取消信号传递、户端与服务器之间的信息传递、置请求超时时间 等

// 通道关闭子协程
func ContextCase() {
	/*
		background := context.Background()
		// 设置个值
		context.WithValue(background, "desc", "ContextCase")
		// 设置超时时间
		background, cancelFunc := context.WithTimeout(background, time.Second*2)
		// 最后取消
		defer cancelFunc()

	*/

	done := make(chan struct{})
	// 执行2个协程
	go f1(done)
	go f1(done)
	// 主线程休眠3秒
	time.Sleep(3 * time.Second)
	close(done) // 关闭通道
}

func f1(done chan struct{}) {
	for {
		select {
		case <-done:
			fmt.Println("协程退出")
			return
		}
	}
}

// context 关闭子协程
func ContextCase2() {
	// 创建context根节点
	background := context.Background()
	// 塞值键值对，返回一个新的context，不过赋值给父context了
	background = context.WithValue(background, "desc", "主线程Context")
	// 设置超时时间，超过超时时间定义的context不生效
	background, cancelFunc := context.WithTimeout(background, time.Second*2)
	// 主线程最后取消，手动取消后定义的centext也不生效
	defer cancelFunc()

	data := [][]int{{1, 2}, {3, 4}}
	ch := make(chan []int)
	go calculate(background, ch) // 执行子协程
	for i := 0; i < len(data); i++ {
		ch <- data[i]
	}
}
func calculate(ctx context.Context, data <-chan []int) {
	for {
		select {
		case item := <-data:
			ctx := context.WithValue(ctx, "desc", "子线程Context")

			ch := make(chan []int)
			go sumContext(ctx, ch)
			ch <- item

			ch2 := make(chan []int)
			go multiContext(ctx, ch2)
			ch2 <- item

		case <-ctx.Done():
			desc := ctx.Value("desc").(string)
			fmt.Printf("calculate协程退出，context desc: %s, 错误消息：%s \n", desc, ctx.Err())
			return
		}
	}
}
func sumContext(ctx context.Context, data <-chan []int) {
	for {
		select {
		case item := <-data:
			a, b := item[0], item[1]
			res := sum(a, b)
			fmt.Printf("%d + %d = %d\n", a, b, res)
		case <-ctx.Done():
			desc := ctx.Value("desc").(string)
			fmt.Printf("sumContext协程退出，context desc: %s, 错误消息：%s \n", desc, ctx.Err())
			return
		}
	}
}
func multiContext(ctx context.Context, data <-chan []int) {
	for {
		select {
		case item := <-data:
			a, b := item[0], item[1]
			res := multi(a, b)
			fmt.Printf("%d * %d = %d\n", a, b, res)
		case <-ctx.Done():
			desc := ctx.Value("desc").(string)
			fmt.Printf("multiContext协程退出，context desc: %s, 错误消息：%s \n", desc, ctx.Err())
			return
		}
	}
}

func sum(a, b int) int {
	return a + b
}
func multi(a, b int) int {
	return a * b
}
